<template>
  <div id="app" style="width: 100%;height: 100%;margin: 0 auto;text-align: center">
    <div v-show="step==='start'" class="start">
      <h2 class="name" style="padding-top: 10%">免费在线多人协作白板</h2>
      <div class="op" style="padding-top: 15px">
        <span>您可以点击快速开始创建自己的画板 或输入画板号加入画板</span>
      </div>
      <div class="chose" style="padding-top: 50px;">
        <div>
          <el-input v-model="st.input" placeholder="请输入画板id" size="mini" style="width: 210px"></el-input>
        </div>
        <div>
          <el-button type="primary" size="mini" plain style="width: 100px;margin-top: 15px"
                     @click="start()">快 速 开 始
          </el-button>
          <el-button type="primary" size="mini" plain style="width: 100px;margin-top: 15px"
                     @click="join()" :disabled="st.input===''">加 入 画 板
          </el-button>
        </div>
      </div>
    </div>
    <div class="use" v-show="step==='use'" style="margin-top: 5%">
      <div>
        <h3 style="color:rgb(220,102,139)">共享ID：{{ query.cid }}，快邀请小伙伴一起来吧~</h3>
      </div>
      <div class="shapes" style="width:850px;text-align: left;margin-top: 3%">
        <el-button v-for="(item,idx) in shapes" @click="changeShape(idx)"
                   :disabled="idx===canvas.currentShape"
                   type="info" plain size="mini">{{ item.name }}
        </el-button>
        <!--        <el-button @click="clearCanvas" style="margin-left: 15px" size="mini">清空</el-button>-->
        <el-checkbox v-model="query.shape.fill" style="margin-left: 15px">填充</el-checkbox>
        <el-link type="info" :underline="false" style="margin-left: 15px">线条颜色</el-link>
        <div class="color">
          <el-color-picker v-model="query.shape.strokeStyle" size="mini" show-alpha></el-color-picker>
        </div>
        <el-link type="info" :underline="false" style="margin-left: 40px">填充颜色</el-link>
        <div class="color">
          <el-color-picker @change="changeFillColor" v-model="query.shape.fillStyle" size="mini" show-alpha></el-color-picker>
        </div>
        <div style="display: inline-block;margin-left: 50px">
          <el-switch
              :disabled="room.rid!==query.uid"
              style="display: block"
              @change="changeMod"
              v-model="room.mod"
              active-color="#13ce66"
              inactive-color="#ff4949"
              active-text="协作"
              inactive-text="只读">
          </el-switch>
        </div>
        <el-button @click="undo" size="mini" type="info" plain style="margin-left: 5px">撤销</el-button>
        <el-button @click="redo" size="mini" type="info" plain>重做</el-button>
        <div style="margin: 15px 0;text-align: left" v-show="query.shape.type==='text'">
          <el-input v-model="st.input" placeholder="请输入内容" size="mini" style="width: 250px"></el-input>
          <el-link type="info" :underline="false" style="margin-left: 15px">输入内容后左键单击需要插入的位置~</el-link>
          <div style="text-align: left">
            <el-link type="info" :underline="false" style="margin-top: 5px">文本尺寸：</el-link>
            <div style="display: inline-block;position: absolute;padding-bottom: 5px">
              <el-slider v-model="canvas.size" style="width: 200px" @input="changeSize"></el-slider>
            </div>
            <div style="display: inline-block;margin-left: 250px">
              <span class="view-text" :style="styles">文本样式预览</span>
            </div>
          </div>
        </div>
      </div>
      <div class="canvas" style="margin-top: 2px">
        <canvas id="canvas" width="850" height="500" style="background-color: #bbb8b8">
          抱歉，您的浏览器不支持canvas元素
        </canvas>
      </div>
      <div class="sheets" style="width:850px;text-align: left;">
        <el-button v-for="(item,idx) in room.canvas" @click="changeSheet(item)"
                   :disabled="item.name===query.cid"
                   type="info" plain size="mini">{{ item.name.slice(-6) }}
        </el-button>
        <el-button type="info" plain size="mini" @click="addSheet">添加画布</el-button>
      </div>
    </div>
  </div>
</template>
<script>

import constant from "@/js/constant";

export default {
  name: 'App',
  data() {
    return {
      step: "start",
      st: {
        input: "",
        wsUrl: "ws://127.0.0.1:10086/websocket",
        // wsUrl: "ws://192.168.2.122:10086/websocket",
      },
      shapes: [
        {name: "直线", type: constant.SHAPE_LINE},
        {name: "箭头", type: constant.SHAPE_ARROW},
        {name: "矩形", type: constant.SHAPE_RECT},
        {name: "圆形", type: constant.SHAPE_CIRCLE},
        {name: "文本", type: constant.SHAPE_TEXT},
      ],
      room: {
        mod: true,
        rid: "",
        canvas: [{name: "sheet1", shapes: []}, {name: "sheet2", shapes: []}],
      },
      canvas: {
        mousedown: false,
        context: "",
        canvas: "",
        canvasing: false,
        currentShape: -1,
        size: 5,
        textSize: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      },
      query: {
        uid: "",
        rid: "",
        cid: "",
        toCid: "",
        type: "",
        shape: {
          type: "",
          x: 0,
          y: 0,
          x1: 0,
          y1: 0,
          fill: false,
          context: "",
          fillStyle: 'rgba(75,129,232,0.8)',
          strokeStyle: 'rgba(232,71,128,0.8)'
        },
      },
      styles: {
        color: 'rgba(75,129,232,0.8)',
        fontSize: 5 + 'px'
      }
    }
  },
  beforeMount() {
    let uid = localStorage.getItem("uid")
    if (uid && uid.length === 16) {
      this.query.uid = uid
    }
  },
  mounted() {
    this.initWs()
    this.initCanvas()
  },
  methods: {
    initWs() {
      if (typeof (WebSocket) === "undefined") {
        this.$message.error('your browser does not support WebSocket...');
      } else {
        this.websocket = new WebSocket(this.st.wsUrl);
        this.websocket.onopen = this.onOpen;
        this.websocket.onerror = this.onError;
        this.websocket.onmessage = this.onMessage;
        this.websocket.onclose = this.onclose;
      }
    },
    initCanvas() {
      let canvas = document.getElementById("canvas");
      let that = this
      if (canvas.getContext) {
        this.canvas.canvas = canvas
        this.canvas.context = canvas.getContext("2d")
        canvas.addEventListener("mousedown", function (e) {
          that.canvas.mousedown = true
          let x = e.x - canvas.getBoundingClientRect().left
          let y = e.y - canvas.getBoundingClientRect().top
          that.query.shape.x = x
          that.query.shape.y = y
          if (that.canvas.currentShape === 4) {
            if (that.st.input !== "") {
              let q = that.query
              q.shape.type = constant.SHAPE_TEXT
              q.shape.context = that.st.input
              q.type = constant.OP_PAINT
              q.shape.x1 = that.canvas.size
              that.sendMessage(q)
            }
          }
        })
        canvas.addEventListener("mouseup", function (e) {
          that.canvas.mousedown = false
          if (that.canvas.canvasing) {
            let x = e.x - canvas.getBoundingClientRect().left
            let y = e.y - canvas.getBoundingClientRect().top
            that.query.shape.x1 = x
            that.query.shape.y1 = y
            that.handlerEvent("mouseup")
          }
        })
        canvas.addEventListener("mousemove", function (e) {
          if (that.canvas.canvasing && that.canvas.mousedown) {
            let x = e.x - canvas.getBoundingClientRect().left
            let y = e.y - canvas.getBoundingClientRect().top
            that.query.shape.x1 = x
            that.query.shape.y1 = y
            that.handlerEvent("mousemove")
          }
        })
      } else {
        this.$message.error('failed to load canvas...');
      }
    },
    handlerEvent(type) {
      let query = this.query
      if (type === "mousemove") {
        query.shape.context = ""
        query.type = constant.OP_PREVIEW
      } else if (type === "mouseup") {
        query.type = constant.OP_PAINT
      }
      this.sendMessage(query)
    },
    start() {
      let query = this.query
      query.type = constant.OP_START
      this.sendMessage(query)
    },
    join() {
      let query = this.query
      query.cid = this.st.input
      query.type = constant.OP_JOIN
      this.sendMessage(query)
    },
    changeSize(size) {
      this.styles = {
        color: this.query.shape.fillStyle,
        fontSize: size + 'px'
      }
    },
    changeFillColor(color) {
      this.styles = {
        color: color,
        fontSize: this.canvas.size + 'px'
      }
      // console.log(color)
      // this.styles.color = 'color: ' + color
    },
    changeMod(mod) {
      console.log(mod)
      let query = this.query
      query.type = constant.OP_CHMOD
      this.sendMessage(query)
    },
    changeShape(idx) {
      this.canvas.canvasing = true
      this.canvas.currentShape = idx
      this.query.shape.type = this.shapes[idx].type
      if (idx === 4) {
        this.canvas.canvasing = false
      }
    },
    changeSheet(cid) {
      let query = this.query
      query.type = constant.OP_CH_CANVAS
      query.toCid = cid.name
      this.sendMessage(query)
    },
    addSheet() {
      let query = this.query
      query.type = constant.OP_ADD_CANVAS
      this.sendMessage(query)
    },
    onMessage(msg) {
      let resp = JSON.parse(msg.data)
      console.log("get data:")
      console.log(resp)
      if (resp !== "") {
        this.dispatchMessage(resp)
      }
    },
    dispatchMessage(resp) {
      if (resp.type === constant.OP_START || resp.type === constant.OP_JOIN) {
        this.room.rid = resp.rid
        this.room.canvas = resp.canvasList
        this.query.uid = resp.uid
        this.query.rid = resp.rid
        this.query.cid = resp.cid
        this.step = 'use'
        for (let i = 0; i < resp.canvasList.length; i++) {
          if (resp.canvasList[i].name === resp.cid) {
            this.room.mod = resp.canvasList[i].chmod
            let shapes = resp.canvasList[i].shapes
            for (let j = 0; j < shapes.length; j++) {
              this.paint(shapes[j])
            }
            break
          }
        }
        localStorage.setItem("uid", resp.uid)
      } else if (resp.type === constant.OP_PAINT || resp.type === constant.OP_PREVIEW
          || resp.type === constant.OP_UNDO || resp.type === constant.OP_REDO) {
        let canvasList = resp.canvasList
        for (let i = 0; i < canvasList.length; i++) {
          if (canvasList[i].name === this.query.cid) {
            let shapes = canvasList[i].shapes
            this.clearCanvas()
            for (let j = 0; j < shapes.length; j++) {
              this.paint(shapes[j])
            }
            break
          }
        }
      } else if (resp.type === constant.OP_ADD_CANVAS) {
        let list = resp.canvasList
        console.log(resp)
        this.room.canvas = list
        if (resp.uid === this.query.uid) {
          this.query.cid = list[list.length - 1].name
          this.clearCanvas()
          this.room.mod = true
        }
      } else if (resp.type === constant.OP_CHMOD) {
        if (resp.rid !== this.query.uid) {
          this.room.mod = !this.room.mod
          if (!this.room.mod) {
            this.$message.info("当前画布已锁定")
          } else {
            this.$message.success("当前画布已解锁")
          }
        }
      } else if (resp.type === constant.OP_CH_CANVAS) {
        let list = resp.canvasList
        for (let i = 0; i < list.length; i++) {
          if (this.query.toCid === list[i].name) {
            this.query.cid = list[i].name
            this.room.mod = list[i].chmod
            let shapes = list[i].shapes
            this.clearCanvas()
            for (let j = 0; j < shapes.length; j++) {
              this.paint(shapes[j])
            }
            break
          }
        }
      }
    },
    undo() {
      let query = this.query
      query.type = constant.OP_UNDO
      this.sendMessage(query)
    },
    redo() {
      let query = this.query
      query.type = constant.OP_REDO
      this.sendMessage(query)
    },
    paint(shape) {
      let type = shape.type
      let context = this.canvas.context
      context.save()
      context.beginPath()
      context.fillStyle = shape.fillStyle
      context.strokeStyle = shape.strokeStyle
      if (type === constant.SHAPE_LINE) {
        context.moveTo(shape.x, shape.y)
        context.lineTo(shape.x1, shape.y1)
        context.stroke();
      } else if (type === constant.SHAPE_ARROW) {
        let fromX = shape.x
        let fromY = shape.y
        let toX = shape.x1
        let toY = shape.y1
        let theta = 30
        let headLen = 5
        let angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,
            angle1 = (angle + theta) * Math.PI / 180,
            angle2 = (angle - theta) * Math.PI / 180,
            topX = headLen * Math.cos(angle1),
            topY = headLen * Math.sin(angle1),
            botX = headLen * Math.cos(angle2),
            botY = headLen * Math.sin(angle2);
        let arrowX = fromX - topX,
            arrowY = fromY - topY;
        context.moveTo(arrowX, arrowY);
        context.moveTo(fromX, fromY);
        context.lineTo(toX, toY);
        arrowX = toX + topX;
        arrowY = toY + topY;
        context.moveTo(arrowX, arrowY);
        context.lineTo(toX, toY);
        arrowX = toX + botX;
        arrowY = toY + botY;
        context.lineTo(arrowX, arrowY);
        context.stroke();
      } else if (type === constant.SHAPE_RECT) {
        let w = shape.x1 - shape.x
        let h = shape.y1 - shape.y
        if (shape.fill) {
          context.fillRect(shape.x, shape.y, w, h);
        }
        context.strokeRect(shape.x, shape.y, w, h);
      } else if (type === constant.SHAPE_CIRCLE) {
        let dis = (shape.x - shape.x1) * (shape.x - shape.x1)
            + (shape.y - shape.y1) * (shape.y - shape.y1)
        dis = Math.sqrt(dis)
        context.arc(shape.x, shape.y, dis, 0, Math.PI * 2);
        if (shape.fill) {
          context.fill();
        }
        context.stroke();
      } else if (type === constant.SHAPE_TEXT) {
        console.log(shape)
        context.font = shape.x1 + 'px Arial'
        context.fillText(shape.context, shape.x, shape.y);
      }
      context.restore()
    },
    clearCanvas() {
      let w = this.canvas.canvas.width
      this.canvas.canvas.width = w
    },
    sendMessage(query) {
      console.log("sent message:" + JSON.stringify(query))
      this.websocket.send(JSON.stringify(query));
    },
    onOpen() {
      console.log("websocket连接成功")
    },
    onError(e) {
      console.log("连接错误");
      console.log(e)
    },
    onclose(e) {
      console.log('WebSocket 断开连接', e);
    },
  },
  destroyed() {
    this.websocket.close();
  },
}
</script>

<style>

* {
  margin: 0 auto;
  padding: 0;
  text-align: center;
}

p {
  color: rgb(86, 91, 97);
}

.color {
  display: inline-block;
  position: absolute;
}
</style>
